﻿#ifndef UTIL_UTIL_H_
#define UTIL_UTIL_H_

#include <cstring>
#include <string>
#include <sstream>
#include <memory>
#include <atomic>

#include "FunctionTraits.h"
#include "ScopeGuard.h"

#ifndef PATH_MAX
#define PATH_MAX 1024
#endif // !PATH_MAX

#define INSTANCE_IMP(class_name, ...) \
class_name &class_name::Instance() { \
    static std::shared_ptr<class_name> s_instance(new class_name(__VA_ARGS__)); \
    static class_name &s_instance_ref = *s_instance; \
    return s_instance_ref; \
}

namespace toolkit {

// 将不同类型的数据组合成一个字符串。类似 std::cout
#define StrPrinter ::toolkit::_StrPrinter()
class _StrPrinter : public std::string {
  public:
    _StrPrinter() {}

    template <typename T> _StrPrinter &operator<<(T &&data) {
        _stream << std::forward<T>(data);
        this->std::string::operator=(_stream.str());
        return *this;
    }

    std::string operator<<(std::ostream &(*f)(std::ostream &)) const {
        return *this;
    }

  private:
    std::stringstream _stream;
};

// 禁止拷贝基类
class NonCopyable {
  protected:
    NonCopyable() {}
    ~NonCopyable() {}

  private:
    // 禁止拷贝
    NonCopyable(const NonCopyable &that) = delete;
    NonCopyable(NonCopyable &&that) = delete;
    NonCopyable &operator=(const NonCopyable &that) = delete;
    NonCopyable &operator=(NonCopyable &&that) = delete;
};

#ifndef CLASS_FUNC_TRAITS
// 用于生成检查类是否具有特定成员函数的功能，以及调用该成员函数的功能。
// funcName 是要检查和调用的成员函数名的后缀
#define CLASS_FUNC_TRAITS(funcName) \
template<typename T, typename ... Args> \
constexpr bool has##funcName(decltype(&T::on##funcName) /*unused*/) { \
    using Ret = typename FunctionTraits<decltype(&T::on##funcName)>::returnType; \
    using FuncType = Ret (T::*)(Args...);   \
    return std::is_same_v<decltype(&T::on##funcName), FuncType>; \
} \
\
template<class T, typename ... Args> \
constexpr bool has##funcName(...) { \
    return false; \
} \
\
template<typename T, typename ... Args> \
static void invokeFunc##funcName(typename std::enable_if_t<!has##funcName<T, Args...>(nullptr), T> &obj, Args ...args) {} \
\
template<typename T, typename ... Args>\
static typename FunctionTraits<decltype(&T::on##funcName)>::returnType invokeFunc##funcName(typename std::enable_if_t<has##funcName<T, Args...>(nullptr), T> &obj, Args ...args) {\
    return obj.on##funcName(std::forward<Args>(args)...);\
}
#endif //CLASS_FUNC_TRAITS

#ifndef CLASS_FUNC_INVOKE
// 用于调用由 CLASS_FUNC_TRAITS 宏生成的 invokeFunc##funcName 函数
#define CLASS_FUNC_INVOKE(T, obj, funcName, ...) invokeFunc##funcName<T>(obj, ##__VA_ARGS__)
#endif //CLASS_FUNC_INVOKE

// 析构函数特性
CLASS_FUNC_TRAITS(Destory)
// 创建函数特性
CLASS_FUNC_TRAITS(Create)

/**
 * 对象安全的构建和析构,构建后执行onCreate函数,析构前执行onDestory函数
 * 在函数onCreate和onDestory中可以执行构造或析构中不能调用的方法，比如说shared_from_this或者虚函数
 * @warning onDestory函数确保参数个数为0；否则会被忽略调用
 */
class Creator {
  public:
    /**
     * 创建对象，用空参数执行onCreate和onDestory函数
     * @param args 对象构造函数参数列表
     * @return args对象的智能指针
     */
    template <typename C, typename... ArgsType>
    static std::shared_ptr<C> create(ArgsType &&...args) {
        std::shared_ptr<C> ret(new C(std::forward<ArgsType>(args)...),
            [](C *ptr) {
                try {
                    CLASS_FUNC_INVOKE(C, *ptr, Destory);
                } catch (std::exception &ex) {
                    onDestoryException(typeid(C), ex);
                }
                delete ptr;
            });
        CLASS_FUNC_INVOKE(C, *ret, Create);
        return ret;
    }

    /**
     * 创建对象，用指定参数执行onCreate函数
     * @param args 对象onCreate函数参数列表
     * @warning
     * args参数类型和个数必须与onCreate函数类型匹配(不可忽略默认参数)，否则会由于模板匹配失败导致忽略调用
     * @return args对象的智能指针
     */
    template <typename C, typename... ArgsType>
    static std::shared_ptr<C> create2(ArgsType &&...args) {
        std::shared_ptr<C> ret(new C(), [](C *ptr) {
            try {
                CLASS_FUNC_INVOKE(C, *ptr, Destory);
            } catch (std::exception &ex) {
                onDestoryException(typeid(C), ex);
            }
            delete ptr;
        });
        CLASS_FUNC_INVOKE(C, *ret, Create, std::forward<ArgsType>(args)...);
        return ret;
    }

  private:
    static void onDestoryException(const std::type_info &info,
                                   const std::exception &ex);

  private:
    Creator() = default;
    ~Creator() = default;
};

template <class C> class ObjectStatistic {
  public:
    ObjectStatistic() { ++getCounter(); }

    ~ObjectStatistic() { --getCounter(); }

    static size_t count() { return getCounter().load(); }

  private:
    static std::atomic<size_t> &getCounter();
};

#define StatisticImp(Type)  \
    template<> \
    std::atomic<size_t>& ObjectStatistic<Type>::getCounter(){ \
        static std::atomic<size_t> instance(0); \
        return instance; \
    }

class AssertFailedException : public std::runtime_error {
public:
    template<typename ...T>
    AssertFailedException(T && ...args) : std::runtime_error(std::forward<T>(args)...) {}
};

std::string makeRandStr(int sz, bool printable = true);
std::string hexDump(const void *buf, size_t len);
std::string hexMem(const void* buf, size_t len);
std::string exePath(bool isExe = true);
std::string exeDir(bool isExe = true);
std::string exeName(bool isExe = true);

std::vector<std::string> split(const std::string& s, const char *delim);
// 去除前后的空格、回车符、制表符...
std::string& trim(std::string &s, const std::string &chars=" \r\n\t");
std::string trim(std::string &&s, const std::string &chars=" \r\n\t");
// string转小写
std::string &strToLower(std::string &str);
std::string strToLower(std::string &&str);
// string转大写
std::string &strToUpper(std::string &str);
std::string strToUpper(std::string &&str);
// 替换子字符串
void replace(std::string &str, const std::string &old_str, const std::string &new_str, std::string::size_type b_pos = 0);
// 判断是否为ip
bool isIP(const char *str);
// 字符串是否以xx开头
bool startWith(const std::string &str, const std::string &substr);
// 字符串是否以xx结尾
bool endWith(const std::string &str, const std::string &substr);
// 拼接格式字符串
template<typename... Args>
std::string strFormat(const std::string &format, Args... args) {

    // 计算缓冲区大小
    auto size_buf = snprintf(nullptr, 0, format.c_str(), args ...) + 1;
    // 分配缓冲区
#if __cplusplus >= 201703L
    // C++17
    auto buf = std::make_unique<char[]>(size_buf);
#else
    // C++11
    std:: unique_ptr<char[]> buf(new(std::nothrow) char[size_buf]);
#endif
    // 检查分配是否成功
    if (buf == nullptr) {
        return {};
    }
    // 用格式化字符串填充缓冲区
    auto result = snprintf(buf.get(), size_buf, format.c_str(), args ...);
    // 返回格式化字符串
    return std::string(buf.get(), buf.get() + result);
}

#ifndef bzero
#define bzero(ptr,size)  memset((ptr),0,(size));
#endif //bzero

#if defined(ANDROID)
template <typename T>
std::string toString(T value){
    std::ostringstream os;
    os << std::forward<T>(value);
    return os.str();
}
#endif//ANDROID

#if defined(_WIN32)
int gettimeofday(struct timeval *tp, void *tzp);
void usleep(int micro_seconds);
void sleep(int second);
int vasprintf(char **strp, const char *fmt, va_list ap);
int asprintf(char **strp, const char *fmt, ...);
const char *strcasestr(const char *big, const char *little);

#if !defined(strcasecmp)
    #define strcasecmp _stricmp
#endif

#if !defined(strncasecmp)
#define strncasecmp _strnicmp
#endif

#ifndef ssize_t
    #ifdef _WIN64
        #define ssize_t int64_t
    #else
        #define ssize_t int32_t
    #endif
#endif
#endif //WIN32

/**
 * 获取时间差, 返回值单位为秒
 */
long getGMTOff();

/**
 * 获取1970年至今的毫秒数
 * @param systemTime 是否为系统时间(系统时间可以回退),否则为程序启动时间(不可回退)
 */
uint64_t getCurrentMillisecond(bool systemTime = false);

/**
 * 获取1970年至今的微秒数
 * @param systemTime 是否为系统时间(系统时间可以回退),否则为程序启动时间(不可回退)
 */
uint64_t getCurrentMicrosecond(bool systemTime = false);

/**
 * 获取时间字符串
 * @param fmt 时间格式，譬如%Y-%m-%d %H:%M:%S
 * @return 时间字符串
 */
std::string getTimeStr(const char *fmt, time_t time = 0);

/**
 * 根据unix时间戳获取本地时间
 * @param sec unix时间戳
 * @return tm结构体
 */
struct tm getLocalTime(time_t sec);

/**
 * 设置线程名
 */
void setThreadName(const char *name);

/**
 * 获取线程名
 */
std::string getThreadName();

/**
 * 设置当前线程cpu亲和性
 * @param i cpu索引，如果为-1，那么取消cpu亲和性
 * @return 是否成功，目前只支持linux
 */
bool setThreadAffinity(int i);

/**
 * 根据typeid(class).name()获取类名
 */
std::string demangle(const char *mangled);

/**
 * 获取环境变量内容，以'$'开头
 */
std::string getEnv(const std::string &key);

// 可以保存任意的对象
class Any {
public:
    using Ptr = std::shared_ptr<Any>;

    Any() = default;
    ~Any() = default;

    Any(const Any &that) = default;
    Any(Any &&that) {
        _type = that._type;
        _data = std::move(that._data);
    }

    Any &operator=(const Any &that) = default;
    Any &operator=(Any &&that) {
        _type = that._type;
        _data = std::move(that._data);
        return *this;
    }

    template <typename T, typename... ArgsType>
    void set(ArgsType &&...args) {
        _type = &typeid(T);
        _data.reset(new T(std::forward<ArgsType>(args)...), [](void *ptr) { delete (T *)ptr; });
    }

    template <typename T>
    void set(std::shared_ptr<T> data) {
        if (data) {
            _type = &typeid(T);
            _data = std::move(data);
        } else {
            reset();
        }
    }

    template <typename T>
    T &get(bool safe = true) {
        if (!_data) {
            throw std::invalid_argument("Any is empty");
        }
        if (safe && !is<T>()) {
            throw std::invalid_argument("Any::get(): " + demangle(_type->name()) + " unable cast to " + demangle(typeid(T).name()));
        }
        return *((T *)_data.get());
    }

    template <typename T>
    const T &get(bool safe = true) const {
        return const_cast<Any &>(*this).get<T>(safe);
    }

    template <typename T>
    bool is() const {
        return _type && typeid(T) == *_type;
    }

    operator bool() const { return _data.operator bool(); }
    bool empty() const { return !bool(); }

    void reset() {
        _type = nullptr;
        _data = nullptr;
    }

    Any &operator=(std::nullptr_t) {
        reset();
        return *this;
    }

    std::string typeName() const {
        if (!_type) {
            return "";
        }
        return demangle(_type->name());
    }

private:
    const std::type_info* _type = nullptr;
    std::shared_ptr<void> _data;
};

// 用于保存一些外加属性
class AnyStorage : public std::unordered_map<std::string, Any> {
public:
    AnyStorage() = default;
    ~AnyStorage() = default;
    using Ptr = std::shared_ptr<AnyStorage>;
};

template <class R, class... ArgTypes>
class FunctionSafe;


template <typename R, typename... ArgTypes>
class FunctionSafe<R(ArgTypes...)> {
public:
    using func = std::function<R(ArgTypes...)>;
    using thisType = FunctionSafe<R(ArgTypes...)>;

    template <class F>
    using enableIfNotThis = typename std::enable_if<!std::is_same<thisType, typename std::decay<F>::type>::value, typename std::decay<F>::type>::type;

    R operator()(ArgTypes... args) const {
        ScopeGuard sg([&]() { _doing = true; checkUpdate(); }, [&]() { checkUpdate(); _doing = false; });
        if (!_impl) {
            throw std::invalid_argument("try to invoke a empty functional");
        }
        return _impl(std::forward<ArgTypes>(args)...);
    }

    FunctionSafe(std::nullptr_t) {
        update(func{});
    }

    FunctionSafe &operator=(std::nullptr_t) {
        update(func{});
        return *this;
    }

    template <typename F, typename = enableIfNotThis<F>>
    FunctionSafe(F &&f) {
        update(func { std::forward<F>(f) });
    }

    template <typename F, typename = enableIfNotThis<F>>
    thisType &operator=(F &&f) {
        update(func { std::forward<F>(f) });
        return *this;
    }

    FunctionSafe() = default;
    FunctionSafe(thisType &&) = default;
    FunctionSafe(const thisType &) = default;
    thisType &operator=(thisType &&) = default;
    thisType &operator=(const thisType &) = default;

    operator bool() const { return _update ? (bool)_tmp : (bool)_impl; }

private:
    void checkUpdate() const {
        if (_update) {
            _update = false;
            _impl = std::move(_tmp);
        }
    }
    void update(func in) {
        if (!_doing) {
            // 没在执行中，那么立即覆写
            _impl = std::move(in);
            _tmp = nullptr;
            _update = false;
        } else {
            // 正在执行中，延后覆写
            _tmp = std::move(in);
            _update = true;
        }
    }

private:
    mutable bool _update = false;
    mutable bool _doing = false;
    mutable func _tmp;
    mutable func _impl;
};

}  // namespace toolkit

#ifdef __cplusplus
extern "C" {
#endif
extern void Assert_Throw(int failed, const char *exp, const char *func, const char *file, int line, const char *str);
#ifdef __cplusplus
}
#endif

#include <list>
#include <type_traits>
template<typename T>
class List : public std::list<T> {
public:
    template<typename ... ARGS>
    List(ARGS &&...args) : std::list<T>(std::forward<ARGS>(args)...) {};

    ~List() = default;

    void append(List<T> &other) {
        if (other.empty()) {
            return;
        }
        this->insert(this->end(), other.begin(), other.end());
        other.clear();
    }

    template<typename FUNC>
    void for_each(FUNC &&func) {
        for (auto &t : *this) {
            func(t);
        }
    }

    template<typename FUNC>
    void for_each(FUNC &&func) const {
        for (auto &t : *this) {
            func(t);
        }
    }
};

#include <iostream>
class Trace {
public:
    template <typename T>
    Trace& operator<<(const T& value) {
        std::cout << value << std::endl;
        return *this;
    }

    Trace& operator<<(std::ostream& (*manip)(std::ostream&)) {
        manip(std::cout);
        return *this;
    }
};

static Trace TraceL;
#define WarnL TraceL
#define Log TraceL

#endif /* UTIL_UTIL_H_ */